const db = require('./db');
var utils = require('./utils');
var exec = require('child_process').exec;
var os = require('os');
var url = require('url');
var qs = require('querystring');

var exports = {};

var parseInput = exports.parseInput = function (str) {
	var matches = str.match(/^\[([^\[\]]+)\](.*)$/i);
	var result = {
		input: str,
		server: false,
		project: false,
		command: false,
		userId: 0,
		args: [],
		taskId: 0,
		executeCommand: ''
	};
	if (matches) {
		var cmd = parseCmd(matches[1]);
		result.server = cmd[0] || false;
		result.project = cmd[1] || false;
		result.command = cmd[2] || false;
		result.args = parseArgs(matches[2]);
	}
	return result;
};

var parseCmd = exports.parseCmd = function (cmd) {
	var args = cmd.split('|');
	var result = [];
	for (var i = 0; i < args.length; i++) {
		if (args[i].length > 0)
			result.push(args[i]);
		else
			result.push(false);
	}
	return result;
};

var parseArgs = exports.parseArgs = function (str) {
	var args = str.split(' ');
	var result = [];
	for (var i = 0; i < args.length; i++) {
		if (args[i].length > 0)
			result.push(args[i]);
	}
	return result;
};

var projectCache = require('./cache_project');
var serverCache = require('./cache_server');
var commandCache = require('./cache_command');
var sessionCache = require('./cache_session');

var eol = function (msg) {
	return msg + '\r\n';
};

var verifyClient = function (client, input, cb) {
	var parse = url.parse(client.path);
	var query = {};
	if (parse.query)
		query = qs.parse(parse.query);
	if (typeof query.t === 'undefined' || query.t === false || query.t === '') {
		client.sendText(eol("无效的请求！"));
	}
	else {
		sessionCache.load(query.t, function (token, user, isFirst) {
			if (user === false)
				client.sendText(eol("无法识别用户身份"));
			else {
				input.userId = user.id;
				if (isFirst) {
					client.sendText(eol("[" + user.login_id + "] 欢迎回来！"), function() {
						if (typeof cb === 'function')
							cb();
					});
				}
				else {
					if (typeof cb === 'function')
						cb();
				}
			}
		});
	}
};

var execCmd = exports.exec = function (client, input) {
	var cmd = parseInput(input);
	if (!client) {
		throw new Error('Invalid client!');
	}
	if (cmd.command === false) {
		client.sendText(eol('无效的指令！'));
	}
	else {
		verifyClient(client, cmd, function() {
			projectCache.load(cmd.project, function (name, project) {
				console.log(cmd.project);
				if (project === false)
					client.sendText(eol('无效的项目！'));
				else {
					serverCache.load(cmd.server, function (name, server) {
						if (server === false)
							client.sendText(eol('无效的服务器！'));
						else {
							commandCache.load(cmd.command, function (name, command) {
								if (command === false)
									client.sendText(eol('无效的指令！'));
								else {
									preExecute(client, cmd, project, server, command);
								}
							});
						}
					});
				}
			});
		});
	}
};

var preExecute = function (client, input, project, server, command) {
	var error = false;
	var checkDir = parseInt(command.check_dir);
	switch (checkDir) {
		case 1 : // 检查存在
			if (!utils.isDir(project.dir)) {
				error = true;
				client.sendText(eol("项目目录不存在！"));
			}
			break;
		case 2 : // 检查不存在
			if (utils.isDir(project.dir)) {
				error = true;
				client.sendText(eol("项目目录已存在！"));
			}
			break;
	}
	if (error === false) {
		// 检查是否存在阻塞的命令，未完成的
		var blockSql = 'select id, command_id, created_at from task where server_id = ? and project_id = ? and status = 0 and is_block = 1 order by id DESC limit 1';
		var blockArgs = [server.id, project.id];
		db.query(blockSql, blockArgs, function (err, rows) {
			var blockRow = db.row(rows, 0);
			if (blockRow !== false) {
				// 存在阻塞
				commandCache.loadId(blockRow.command_id, function (id, data) {
					var createAt = new Date(blockRow.created_at * 1000);
					client.sendText(eol('[' + data.name + '] blocked, it start at ' + createAt));
				});
			}
			else {
				// 检查当前命令是否仍有未完成的命令
				var isAlone = parseInt(command.is_alone);
				if (isAlone > 0) {
					var aloneSql = 'select id, created_at from task where server_id = ? and project_id = ? and command_id = ? and status = 0 order by id DESC limit 1';
					var aloneArgs = [server.id, project.id, command.id];
					db.query(aloneSql, aloneArgs, function (err, rows, fields) {
						var aloneRow = db.row(rows, 0);
						if (aloneRow !== false) {
							input.taskId = aloneRow.id;
							var createAt = new Date(parseInt(aloneRow.created_at) * 1000);
							client.sendText(eol('[' + input.command + '] not complete at ' + createAt));
						}
						else {
							preExecute2(client, input, project, server, command);
						}
					});
				}
				else {
					preExecute2(client, input, project, server, command);
				}
			}
		});
	}
};

var preExecute2 = function (client, input, project, server, command) {
	var now = new Date(), nowInt = parseInt(now.getTime() / 1000);
	var isAlone = parseInt(command.is_alone);
	if (isAlone > 0) {
		var taskData = {
			user_id: input.userId,
			server_id: server.id,
			project_id: project.id,
			command_id: command.id,
			status: 0,
			is_block: isAlone === 1 ? 0 : 1,
			created_at: nowInt
		};
		db.query('INSERT INTO task SET ?', taskData, function (err, result) {
			if (err)
				client.sendText(eol(err));
			else {
				input.taskId = result.insertId;
				executeLast(client, input, project, server, command, function (error, stdout, stderr, usedTime) {
					db.query('UPDATE task set status = 1, completed_at = ? where id = ?', [nowInt, input.taskId], function () {
						// log
						log(error, stdout, stderr, usedTime, client, input, project, server, command);
					});
				});
			}
		});
	}
	else {
		executeLast(client, input, project, server, command, function (error, stdout, stderr, usedTime) {
			// log
			log(error, stdout, stderr, usedTime, client, input, project, server, command);
		});
	}
};

var executeLast = function (client, input, project, server, command, cb) {
	var cmd = utils.substitute(command.command, project);
	var start = new Date();
	input.executeCommand = cmd;
	client.sendText(eol('[' + input.command + '] start'), function () {
		exec(cmd, function (error, stdout, stderr) {
			var msg = [];
			var hasError = false;
			if (error) {
				msg.push(error);
				hasError = true;
			}
			if (stderr.length > 0)
				msg.push(stderr);
			if (stdout.length > 0)
				msg.push(stdout);
			var end = new Date();
			var usedTime = end.getMilliseconds() - start.getMilliseconds();
			if (usedTime < 0)
				usedTime = 0;
			msg.push('[' + input.command + ']' + " complete, used time " + (usedTime) + 'ms');

			if (typeof cb === 'function') {
				cb.call(this, error, stdout, stderr, usedTime);
			}

			try {
				client.sendText(eol(msg.join('')));
			}
			catch (err) {

			}
		});
	});
};

var log = function (error, stdout, stderr, usedTime, client, input, project, server, command) {
	var now = new Date(), nowInt = parseInt(now.getTime() / 1000);
	var isLog = parseInt(command.is_log);
	if (isLog) {
		var logData = {
			user_id: input.userId,
			server_id: server.id,
			project_id: project.id,
			command_id: command.id,
			used_time: usedTime,
			misc: '',
			created_at: nowInt
		};
		var misc = [
			input.executeCommand,
			error,
			stderr,
			stdout
		];

		logData.misc = misc.join('{-------------------------------------------------------}');
		// 写入日志
		db.query('INSERT INTO task_log SET ?', logData, function (err, rows) {

		});
	}

};

module.exports = exports;